/*
-----------------------------------------------------------------------------
This file is part of NxGraphics, Multimedia Engine.
Author : Stephane Kyles. Developed in Prague, Czech Republic.
				_   __       __  ___                         
			   / | / /_  __ /  |/  /____   _____ ____ _ ____ 
			  /  |/ /| |/_// /|_/ // __ \ / ___// __ `// __ \
			 / /|  /_>  < / /  / // /_/ // /__ / /_/ // /_/ /
			/_/ |_//_/|_|/_/  /_/ \____/ \___/ \__,_// .___/ 
													/_/      
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#ifndef __NXMOCAPPLAYER_H__
#define __NXMOCAPPLAYER_H__

#include "NxMocap_Prerequisites.h"

namespace NxMocap_Namespace {

enum NxMocapTypes {  
	NxMocapPlayerType,
	NxMocapRecorderType,
	NxMocapReceiverType
};

enum NxMocapConvertPacketTypes {  
	Mysql_Memory_PlayBack,
	Mysql_Live_PlayBack,
	Latus_Usb_PlayBack
};

enum NxMocapSensorDataTypes {  
	POSX,
	POSY,
	POSZ,
	ORIX,
	ORIY,
	ORIZ
};

enum NxMocapSensorStatus{ 
	PhaseCalib,
	PhaseLive 
};

class NxMocap_Export NxMocapStreamer
{
public:
	NxMocapStreamer();
	~NxMocapStreamer();
	//streamer
	void CreatePlaybackStream( string IP, int port );
	void DeletePlaybackStream();
	void SetEnablePlaybackStream( bool Use );
	virtual void StartPlayBack();
	string GetStreamingIp();
	int GetStreamingPort();
	SocketClient * mSocketClient ;
	std::string mDestinationIp;
	int mDestinationPort ;
	bool UsePlayBackStream ;
};

typedef enum NxSkeletonJoint
{
	NX_SKEL_HEAD			= 1,
	NX_SKEL_NECK			= 2,
	NX_SKEL_SPINE3			= 3,
	NX_SKEL_SPINE2			= 4,
	NX_SKEL_SPINE1		    = 5,
	NX_SKEL_SPINE	        = 6,
	NX_SKEL_PELVIS   		= 7,
	NX_SKEL_ROOT    		= 8,
	NX_SKEL_L_THIGH 		= 9,
	NX_SKEL_R_THIGH     	=10,
	NX_SKEL_L_CALF      	=11,
	NX_SKEL_R_CALF      	=12,
	NX_SKEL_L_FOOT  		=13,
	NX_SKEL_R_FOOT   		=14,
	NX_SKEL_L_CLAVICLE 		=15,
	NX_SKEL_R_CLAVICLE  	=16,
	NX_SKEL_L_UPPERARM		=17,
	NX_SKEL_R_UPPERARM		=18,
	NX_SKEL_L_FOREARM 		=19,
	NX_SKEL_R_FOREARM		=20,
	NX_SKEL_L_HAND		    =21,
	NX_SKEL_R_HAND		    =22,

} NxSkeletonJoint;

struct NxMocapJoint{
	NxMocapJoint(){
		mPosition[0] = mPosition[1] = mPosition[2] = 0.0f;
		mOrientation[0] = mOrientation[1] = mOrientation[2] = mOrientation[3] = 0.0f;
		mConfidence = 0.0f;
		mName = "Default Joint";
		mIsRoot = false;
	}
	float mPosition[3];
	float mOrientation[4];
	float mConfidence;
	std::string mName;
	NxSkeletonJoint mType;
	bool mIsRoot;
};

//! Skeleton definition for all avatars.
class NxMocap_Export NxMocapSkeleton
{
protected :
	//! NxMocapSkeleton Class Constructor.
	NxMocapSkeleton( unsigned int UserId );
public:
	//! NxMocapSkeleton Class Destructor.
	~NxMocapSkeleton();
	//! get user ID
	const unsigned int GetUserId();
	//! Get Skeleton Joint for Information: Tranlation, Rotation.
	inline bool GetSkeletonJoint( NxSkeletonJoint eJoint, NxMocapJoint& Joint) const;
	//! Get Full Skeleton Joint Information: Tranlation, Rotation.
	inline bool GetSkeletonJoints( std::vector<NxMocapJoint> & JointList ) const;
	//! Get Total Joint Number.
	unsigned int GetNumJoints();
	//! Is current joint the root.
	bool IsRoot( NxMocapJoint Joint );
	//! create a joint.
	void CreateJoint( const std::string& JointName, NxSkeletonJoint Type );
	//! Set Joint Position.
	void SetJointPosition( NxSkeletonJoint Type, float Position[3], float Confidence );
	//! Set joint Orientation.
	void SetJointOrientation( NxSkeletonJoint Type, float Orientation[4] );
private:
	//! Skeleton Joint List.
	std::vector<NxMocapJoint*> mJointList;
	//! User Id
	unsigned int mUserId;
};


class NxMocap_Export NxMocapUser : public NxMocapSkeleton
{
public :
	NxMocapUser( unsigned int UserId );
	~NxMocapUser();
	const unsigned int GetUserId();
	void GetUserPosition( float &X, float &Y, float &Z  );
	void SetUserPosition( float Position[3] );
	void SetSkeletonTracked( bool Tracked );
	//! User has a skeleton ?.
	bool IsSkeletonTracked();
	void SetValid( bool Valid );
	bool IsValid();


private:
	void CreateSkeleton();
	//! User has a skeleton ?.
	bool mSkeletonTracked;
	//! User position.
	float mUserPosition[3];
	bool mValid;
};



//! Base class for all MocapDevices.
class NxMocap_Export NxMocapDevice
{
protected :
	//! NxMocapDevice Class Constructor.
	NxMocapDevice();
public :
	//! NxMocapDevice Class Destructor.
	virtual ~NxMocapDevice();
	//! Connect MocapDevice.
	virtual bool ConnectDevice();
	//! Disconnect MocapDevice.
	virtual bool DisconnectDevice();
	//! update Mocap Device.
	virtual bool Update();
};

//! Kinect MoCap Device Class.
class NxMocap_Export NxMocapDeviceKinect : public NxMocapDevice, public NxMocapMysql, public NxMocapStreamer
{
public :
	//! NxMocapDeviceKinect Class Constructor.
	NxMocapDeviceKinect();
	//! NxMocapDeviceKinect Class Destructor.
	~NxMocapDeviceKinect();
	//! Connect Kinect Device.
	bool ConnectDevice();
	//! Disconnect Kinect Device.
	bool DisconnectDevice();
	//! return is the system is tracking an user.
	bool IsTracking( unsigned int UserID );
	//! Get Number of Users Detected.
	unsigned int GetNumUsers();
	//! Get User By Index
	NxMocapUser * GetUser( unsigned int Index );
	//! Stops tracking users and reset the system ready for new users.
	void Reset();
	//! Update and refresh Kinect Data.
	bool Update();
	//Get point cloud if available
	inline bool GetPointsInfo( float * PointsPosition, unsigned int * Colors, unsigned long & NumParticles, float Scale, float MaxRange );
private:
	//! Kinect Device.
	KinectPlayer * mKinect;
};



class NxMocap_Export NxMocapPlayer : public NxMocapSkeleton, public NxMocapMysql, public NxMocapStreamer
{
public :
	NxMocapPlayer();
	~NxMocapPlayer();
	virtual void ConvertToJoints();
	virtual void SetReferenceFrame( float Azimuth, float Elevation, float Roll );
	virtual void GetReferenceFrame( float &Azimuth, float &Elevation, float &Roll );
	//mysql
	void LoadInMemoryMysql();
	void MysqlSetPlaybackRate( float fps );
	float MysqlGetPlaybackRate();
	void SetLooping( bool value );
	//player
	virtual void StartPlayBack();
	void StopPlayBack();
	void PausePlayback();
	void ResumePlayback();
	bool IsPlaying();
	bool IsStopped();
	bool IsPaused() const  ;
	void SeekTimePosition( float milliseconds );  
	float GetTimePosition() const ;
	void SetInboundPlayBackTime( float milliseconds );
	void SetOutboundPlayBackTime( float milliseconds );
	float GetInboundPlayBackTime();
	float GetOutboundPlayBackTime();
	float GetTotalTrackTime();
	float GetCurrentPlaybackFramerate();
	unsigned long GetMocapStreamID() const ;
	void SetMocapStreamID( unsigned long ID );  
	int GetMocapStreamIndex(); 
	void SetConfigType( NxMocapConvertPacketTypes Type   ); 
	//MYSQL
	//! convert mysql to binary
	void ConvertMocapPacket( NxMocapConvertPacketTypes ConvertType  );
	//! convert mysql to binary
	void Convert_Mysql_To_Memory();
	BYTE * GetTimeData( float milisecond_time );
	BYTE * GetFrameData( long frameNumber );
	bool Player_Is_TimeManual();
	void SetTimeUpdateManual( bool manual );
	NxMocapTypes GetNxMocapType();
	void SetNxMocapType( NxMocapTypes Type );
	protected :

	unsigned long MocapPlayerStreamID;
	int MocapPlayerStreamIndex ;
	//private :
	NxMocapConvertPacketTypes PlayType ;//playback type
	friend DWORD socket_thread_sender( LPVOID lpParameter );
	friend DWORD time_thread(LPVOID lpParameter);
	HANDLE Frame_thread_Handle  ;
	HANDLE Time_thread_Handle  ;
	float PlayBackFramerate ;
	bool PlayBackLooping ;
	long Last_Frame_Num ;

	NxMocapTypes NxMocapType;

	bool Sender_Should_Run ;
	bool FramerateIndexer_Should_Run ;
	bool isCurrentlyPlaying ;
	bool isCurrentlyPaused ;

	float mTimeInbound ;
	float mTimeOutbound ;
	float mTime ;
	float Time_Index_Last ; // last rendered time index

	typedef std::map< unsigned __int64, BYTE * > Packet_Data_Type ;
	typedef std::map< unsigned __int64, int > Packet_Length_Type ;
	Packet_Data_Type Packet_Data ;
	Packet_Length_Type Packet_Length ;
	bool Player_ManualTimeMode ;

protected:

	int frame_rate_index ; 
	int frame_rate_stable ;
	NxMocapDataList DataList;
 
};

//plays polhemus mocap from database
class NxMocap_Export NxMocapPlayerPolhemus : public NxMocapPlayer
{
public :
	NxMocapPlayerPolhemus();
	~NxMocapPlayerPolhemus();
	//! Virutals
	void SetReferenceFrame( float Azimuth, float Elevation, float Roll );
	void GetReferenceFrame( float &Azimuth, float &Elevation, float &Roll );
	void ConvertToJoints();
	//!Streamer Virtuals
	void StartPlayBack();
	void SetLayout( int newLayout[] );
	int * GetLayout();
	void ParseByteToFloatArray( BYTE * Bytes, long count);
	float GetSensorData ( int sensor, NxMocapSensorDataTypes Type ); 
	float GetCalibSensorData ( int sensor, NxMocapSensorDataTypes Type );
	void SetCurrentPhase( NxMocapSensorStatus Phase );
	NxMocapSensorStatus GetCurrentPhase();
	//! Hanim standard
	CHAnim * hanim;
	float SensorData[16][6];
	float CalibSensorData[16][6];
	NxMocapSensorStatus CurrentPhase ; 

};

class NxMocap_Export NxMocapPlayerKinect : public NxMocapPlayer
{
public :
	NxMocapPlayerKinect();
	~NxMocapPlayerKinect();
};

//play kinect data from database
class NxMocap_Export NxMocapPlayerBvh : public NxMocapPlayer
{
public :
	NxMocapPlayerBvh();
	~NxMocapPlayerBvh();
};






}

#endif